#include "parse_contig_pos.h"


#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/tr1/tuple.hpp>
#include <boost/spirit/home/phoenix/core/argument.hpp>
#include <boost/spirit/home/phoenix/algorithm.hpp>
#include <cinttypes>

namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

using std::string;
using std::cerr;
using std::vector;

#include "qi_parse_error_handler.h"

BOOST_FUSION_ADAPT_STRUCT(
t_contig_pos,
(std::string, chromosome)
(long, pos)
(std::string, category)
)


phoenix::function<errorHandlerT> const errorHandler_contig_pos = errorHandlerT("Contig and Position");


template <typename Iterator>
struct contig_pos_grammar
: qi::grammar<Iterator, t_contig_pos()>
{
    contig_pos_grammar(unsigned& cnt_line_)
    : contig_pos_grammar::base_type(contig_pos), cnt_line(cnt_line_)
    {
        using qi::lit;
        using qi::char_;
        using qi::long_;
        using namespace qi::labels;
        using qi::eol;

		tab			%= lit('\t');
        chromosome  %= +(char_ - '\t');
        position    %= long_;  
		category	%= +(char_ - '\t');
        contig_pos  %= -lit("chr") > chromosome 	> tab  
						> position                  > 
						-(tab > category);
        // give names for debug
        tab         		.name("TAB");
        chromosome  		.name("Chromosome");
        position    		.name("Contig position");
		category			.name("Category");
		qi::on_error<qi::fail>                               
        (contig_pos, ::errorHandler_contig_pos(_1, _2, _3, _4, phoenix::ref(cnt_line)));
    }
    unsigned& cnt_line;
    qi::rule<Iterator, std::string()>	chromosome    ;
    qi::rule<Iterator, long()>       	position      ;
	qi::rule<Iterator, std::string()>	category   	;   
    qi::rule<Iterator, void()>      	tab           ;
    qi::rule<Iterator, t_contig_pos()>	contig_pos    ;
};


sp_contig_pos_grammar create_contig_pos_grammar(unsigned& curr_line_number)
{
	return boost::shared_ptr<contig_pos_grammar<std::string::const_iterator> >(new contig_pos_grammar<std::string::const_iterator>(curr_line_number));
}


bool parse_contig_pos(boost::shared_ptr<contig_pos_grammar<std::string::const_iterator> > p_vcf_selected_strain_grammar, string::const_iterator& str_beg, string::const_iterator str_end, t_contig_pos& res)
{
	contig_pos_grammar<std::string::const_iterator>& vcf_selected_strain_grammar = *p_vcf_selected_strain_grammar;
    return qi::parse(str_beg, str_end, vcf_selected_strain_grammar, res);
}
    


